package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gogf/gf/os/glog"
	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
	"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	pb "github.com/wwcd/grpc-lb/cmd/helloworld"
	"github.com/wwcd/grpc-lb/common/trace"
	grpclb "github.com/wwcd/grpc-lb/etcdv3"
	"google.golang.org/grpc"
)

var (
	serv       = flag.String("service", "hello_service", "service name")
	host       = flag.String("host", "192.168.0.101", "listening host")
	port       = flag.String("port", "5001", "listening port")
	reg        = flag.String("reg", "http://192.168.0.101:2379", "register etcd address")
	jaegeraddr = flag.String("jaeger", "192.168.0.101:6831", "Jaeger address")
)
var (
	// Create a metrics registry.
	promReg = prometheus.NewRegistry()

	// Create some standard server metrics.
	grpcMetrics = grpc_prometheus.NewServerMetrics()
)

func main() {
	grpcMetrics.EnableHandlingTimeHistogram()
	promReg.MustRegister(grpcMetrics)
	// Create a HTTP server for prometheus.
	httpServer := &http.Server{Handler: promhttp.HandlerFor(promReg, promhttp.HandlerOpts{}), Addr: fmt.Sprintf("0.0.0.0:%d", 9092)}

	flag.Parse()
	glog.Infof("0.0.0.0: %v", *jaegeraddr)
	tracer, err := trace.New("search", *jaegeraddr)

	lis, err := net.Listen("tcp", net.JoinHostPort("0.0.0.0", *port))
	if err != nil {
		panic(err)
	}

	err = grpclb.Register(*reg, *serv, *host, *port, time.Second*10, 15)
	if err != nil {
		panic(err)
	}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL, syscall.SIGHUP, syscall.SIGQUIT)
	go func() {
		s := <-ch
		glog.Infof("receive signal '%v'", s)
		grpclb.UnRegister()
		os.Exit(1)
	}()

	glog.Infof("starting hello service at %s", *port)
	s := grpc.NewServer(

		grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
			grpcMetrics.UnaryServerInterceptor(),
			otgrpc.OpenTracingServerInterceptor(tracer),
		)),
		grpc.StreamInterceptor(grpcMetrics.StreamServerInterceptor()),
	)
	pb.RegisterGreeterServer(s, &server{})

	// Initialize all metrics.
	grpc_prometheus.EnableHandlingTimeHistogram()
	grpcMetrics.InitializeMetrics(s)

	// Start your http server for prometheus.
	go func() {

		if err := httpServer.ListenAndServe(); err != nil {
			log.Fatal("Unable to start a http server.")
		}

	}()

	s.Serve(lis)
}

// server is used to implement helloworld.GreeterServer.
type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	glog.Infof("%v: Receive is %s\n", time.Now(), in.Name)
	return &pb.HelloReply{Message: "Hello " + in.Name + " from " + net.JoinHostPort(*host, *port)}, nil
}
